#pragma once

#include "Ability/EditorAbilityViewModel.h"
#include "EditorVariableAbilityModel.h"
#include "EditorVariableAbilityViewModel.m.h"

class REditorVariableAbilityModel;

RCLASS()
class REditorVariableAbilityViewModel : public REditorAbilityViewModel
{
    ROBJECT

public:
    void BindModel(TSharedObjectPtr<REditorAbilityModel> InModel) override;
    virtual TSharedObjectPtr<RTexture2D> GetIcon() const override;
    virtual TSharedObjectPtr<RTexture2D> GetHighlightIcon() const override;

protected:
    TWeakObjectPtr<REditorVariableAbilityModel> VariableModel;
    TSharedObjectPtr<RTexture2D> Icon;
    TSharedObjectPtr<RTexture2D> HighlightIcon;

    TSharedObjectPtr<RTexture2D> ExpendedIcon;
    TSharedObjectPtr<RTexture2D> CollapsedIcon;

    struct SVariableNode
    {
        //if IsScope is true, 
        //this node is a scope node, and the children are the variables in this scope
        bool IsScope = false;

        bool bIsExpanded = false;

        CString Name;

        int64_t Depth = 0;

        //the value of the variable
        //only valid when IsScope is false
        CString Value;

        SEditorScriptValueReference Reference;

        bool bHasChildren = false;
    };

    void UpdateNodeList();
    void UpdateNodeChildren(
        const SEditorScriptValueReference & InReference
        , int64_t InParentDepth);

    TVector<std::shared_ptr<SVariableNode>> NodeList;

    TVector<CString> ExpandedScopes;

    TVector<SEditorScriptValueReference> ExpandedValues;

    TVector<SEditorScriptValueReference> RequestingValues;
    
    TMap<SEditorScriptValueReference, TVector<SEditorScriptValue>> RequestedValuesMap;


    void OnChildrenRequested(
        const SEditorScriptValueReference & InReference,
        const TVector<SEditorScriptValue> & InValues
    );


    const float IndentSize = 20.0f;
public:

    const float LineHeight = 20.0f;
    TSharedObjectPtr<RTexture2D> GetNodeIcon(int64_t InIndex) const;


    TDelegate<void> OnListChanged;

    int64_t GetNodeNum() const;
    bool IsNodeScope(int64_t InIndex) const;
    bool IsNodeExpanded(int64_t InIndex) const;
    CString GetNodeName(int64_t InIndex) const;
    CString GetNodeValue(int64_t InIndex) const;
    bool HasNodeChildren(int64_t InIndex) const;
    float GetNodeIndent(int64_t InIndex) const;

    void ToggleNodeExpanded(int64_t InIndex);
};